package pro.shushi.pamirs.hr.core.action;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import pro.shushi.pamirs.hr.api.enums.ApprovalStatusEnum;
import pro.shushi.pamirs.hr.api.enums.HrSimpleExpEnum;
import pro.shushi.pamirs.hr.api.model.biz.ExpenseBill;
import pro.shushi.pamirs.hr.api.model.biz.ExpenseBillDetail;
import pro.shushi.pamirs.hr.api.service.ExpenseBillService;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.annotation.validation.Validation;
import pro.shushi.pamirs.meta.api.dto.common.Message;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
import pro.shushi.pamirs.meta.common.lambda.LambdaUtil;
import pro.shushi.pamirs.meta.constant.ExpConstants;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.*;

import java.math.BigDecimal;
import java.util.List;

@Slf4j
@Component
@Model.model(ExpenseBill.MODEL_MODEL)
public class ExpenseBillAction {

    @Autowired
    private ExpenseBillService expenseBillService;

    /**
     * 自定义构造方法示例
     * 如：界面设计器提交数据-选择的提交函数，新增时系统会调用construct
     * @param data
     * @return
     */
    @Function(openLevel = FunctionOpenEnum.API)
    @Function.Advanced(type = FunctionTypeEnum.QUERY)
    public ExpenseBill construct(ExpenseBill data) {
        data.setSubmitter(PamirsSession.getUserName());
        return data;
    }

    /** Validation也可以使用系统的一些内置函数(https://doc.oinone.top/oio4/9287.html)，
     *  ServerAction检验https://doc.oinone.top/oio4/9255.html，示例：
        @Validation(ruleWithTips = {
            @Validation.Rule(value = "!IS_BLANK(data.code)", error = "编码为必填项"),
            @Validation.Rule(value = "LEN(data.bankAccountNumber) < 20", error = "收款账号过长，不能超过20位"),
        })
     *
     * @param data
     * @return
     */
    @Transactional
    @Validation(check = "checkAmount") // 校验方式1：销单金额与明细金额汇总是否一致. https://doc.oinone.top/oio4/9288.html
    @Action.Advanced(name = FunctionConstants.create, managed = true, invisible = ExpConstants.idValueExist)
    @Action(displayName = "保存", summary = "创建", bindingType = ViewTypeEnum.FORM)
    @Function(name = FunctionConstants.create)
    @Function.fun(FunctionConstants.create)
    public ExpenseBill create(ExpenseBill data) {
        data.construct();
        data.create();
        data.fieldSave(ExpenseBill::getBillDetails);
        return data;
    }

    @Function.Advanced(type = FunctionTypeEnum.UPDATE)
    @Action.Advanced(name = FunctionConstants.update, managed = true,
            // 可以在界面设计器设置如果是非NC状态按钮隐藏掉或者无效
            disable = "activeRecord.approvalStatus != 'NC'",
            invisible = ExpConstants.idValueNotExist)
    @Action(displayName = "更新", summary = "修改", bindingType = ViewTypeEnum.FORM)
    @Function(name = FunctionConstants.update)
    @Function.fun(FunctionConstants.update)
    public ExpenseBill update(ExpenseBill data) {
        expenseBillService.update(data);
        return data;
    }

    @Action(displayName = "删除", contextType = ActionContextTypeEnum.SINGLE_AND_BATCH)
    // 可以在界面设计器设置如果是非NC状态按钮隐藏掉或者无效
    @Action.Advanced(disable = "activeRecord.approvalStatus != 'NC'")
    @Function(name = FunctionConstants.delete)
    @Function.fun(FunctionConstants.deleteWithFieldBatch)
    @Function.Advanced(type = FunctionTypeEnum.DELETE)
    public List<ExpenseBill> delete(List<ExpenseBill> dataList) {
        for (ExpenseBill data : dataList) {
            ExpenseBill dbExpenseBill = new ExpenseBill().setId(data.getId()).queryById();
            if (!ApprovalStatusEnum.NC.equals(dbExpenseBill.getApprovalStatus())) {
                throw PamirsException.construct(HrSimpleExpEnum.EXPENSE_BILL_STATUS_NOT_NC).errThrow();
            }
            data.deleteById();
        }
        return dataList;
    }

    @Action(displayName = "提交", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    // 可以在界面设计器设置如果是非NC状态按钮隐藏掉或者无效
    @Action.Advanced(invisible = "activeRecord.approvalStatus != 'NC'")
    public ExpenseBill submit(ExpenseBill data) {
        ExpenseBill dbExpenseBill = new ExpenseBill().setId(data.getId()).queryById();
        if (!ApprovalStatusEnum.NC.equals(dbExpenseBill.getApprovalStatus())) {
            throw PamirsException.construct(HrSimpleExpEnum.EXPENSE_BILL_STATUS_NOT_NC).errThrow();
        }

        ExpenseBill update = new ExpenseBill();
        update.setId(data.getId());
        update.setApprovalStatus(ApprovalStatusEnum.PENDING);
        update.updateById();
        return data;
    }

    /**
     * 该示例说明：提交数据校验数据
     *
     * 校验方式2：通过在Action的方法上增加：@Validation
     * @param data
     */
    @Function
    public Boolean checkAmount(ExpenseBill data) {
        boolean success = true;
        if (CollectionUtils.isEmpty(data.getBillDetails())) {
            // PamirsSession.getMessageHub().msg(Message.init().setLevel(InformationLevelEnum.ERROR).setMessage("报销单明细为空"));
            PamirsSession.getMessageHub().error("报销单明细为空");
            success = false;
        }

        BigDecimal totalAmount = new BigDecimal("0.0");
        for (ExpenseBillDetail detail: data.getBillDetails()) {
            totalAmount = totalAmount.add(detail.getAmount());
        }
        if (data.getAmount().compareTo(totalAmount) != 0) {
            String amountField = LambdaUtil.fetchFieldName(ExpenseBill::getAmount);
            // 消息提示可以使用下面这两种方式
            PamirsSession.getMessageHub().msg(Message.init().setLevel(InformationLevelEnum.ERROR).setField(amountField)
                    .setMessage("报销单金额错误(明细汇总金额与总报销总金额不相等)"));
            // PamirsSession.getMessageHub().error("报销单金额错误(明细汇总与总报销总金额不相等)");
            success = false;
        }

        return success;
    }

}
